package org.atricore.idbus.capabilities.sso.ui.internal;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.behavior.Behavior;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupElement;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.WicketTag;
import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
import org.apache.wicket.markup.parser.AbstractMarkupFilter;
import org.apache.wicket.markup.parser.filter.RelativePathPrefixHandler;
import org.apache.wicket.markup.resolver.IComponentResolver;
import org.apache.wicket.request.UrlUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
/**
* Work-around to make apache-wicket play nice with servlet context used in OSGi
* Due to extensibility limitations in Apache Wicket, we had to clone&own this class.
*
* @author <a href=mailto:sgonzalez@atricore.org>Sebastian Gonzalez Oyuela</a>
*/
public class IdBusRelativePathPrefixHandler extends AbstractMarkupFilter implements IComponentResolver {
private static final long serialVersionUID = 1L;
/**
* Logging
*/
private static final Logger log = LoggerFactory.getLogger(RelativePathPrefixHandler.class);
/**
* The id automatically assigned to tags without an id which we need to prepend a relative path
* to.
*/
public static final String WICKET_RELATIVE_PATH_PREFIX_CONTAINER_ID = "_relative_path_prefix_";
/**
* List of attribute names considered
*/
private static final String attributeNames[] = new String[]{"href", "src", "background",
"action"};
private String mountPoint;
public IdBusRelativePathPrefixHandler(String mountPoint) {
this.mountPoint = mountPoint;
}
/**
* Behavior that adds a prefix to src, href and background attributes to make them
* context-relative
*/
public final Behavior IDBUS_RELATIVE_PATH_BEHAVIOR = new Behavior() {
private static final long serialVersionUID = 1L;
@Override
public void onComponentTag(Component component, ComponentTag tag) {
/*
IRequestCodingStrategy coder = RequestCycle.get()
.getProcessor()
.getRequestCodingStrategy(); */
// Modify all relevant attributes
for (int i = 0; i < attributeNames.length; i++) {
String attrName = attributeNames[i];
String attrValue = tag.getAttributes().getString(attrName);
if ((attrValue != null) && (attrValue.startsWith("/") == false) &&
(attrValue.indexOf(":") < 0) && !(attrValue.startsWith("#"))) {
if (UrlUtils.isRelative(attrValue)) {
// All resources MUST be relative to mount point, just remove all the ../ added by wicket:
int idx = attrValue.lastIndexOf("../");
String newPath = attrValue.substring(idx + 1);
tag.getAttributes().put(attrName, "/" + mountPoint + "/" + newPath);
}
}
}
}
};
@Override
protected final MarkupElement onComponentTag(ComponentTag tag) throws ParseException
{
if (tag.isClose())
{
return tag;
}
String wicketIdAttr = getWicketNamespace() + ":" + "id";
// Don't touch any wicket:id component and any auto-components
if ((tag instanceof WicketTag) || (tag.isAutolinkEnabled() == true) ||
(tag.getAttributes().get(wicketIdAttr) != null))
{
return tag;
}
// Work out whether we have any attributes that require us to add a
// behavior that prepends the relative path.
for (String attrName : attributeNames)
{
String attrValue = tag.getAttributes().getString(attrName);
if ((attrValue != null) && (attrValue.startsWith("/") == false) &&
(!attrValue.contains(":")) && !(attrValue.startsWith("#")))
{
if (tag.getId() == null)
{
tag.setId(WICKET_RELATIVE_PATH_PREFIX_CONTAINER_ID);
tag.setAutoComponentTag(true);
}
tag.addBehavior(IDBUS_RELATIVE_PATH_BEHAVIOR );
tag.setModified(true);
break;
}
}
return tag;
}
public Component resolve(final MarkupContainer container, final MarkupStream markupStream,
final ComponentTag tag)
{
if ((tag != null) && (tag.getId().startsWith(WICKET_RELATIVE_PATH_PREFIX_CONTAINER_ID)))
{
String id = WICKET_RELATIVE_PATH_PREFIX_CONTAINER_ID +
container.getPage().getAutoIndex();
// we do not want to mess with the hierarchy, so the container has to be
// transparent as it may have wicket components inside. for example a raw anchor tag
// that contains a label.
return new TransparentWebMarkupContainer(id);
}
return null;
}
}